using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Collections;

namespace SAE.Controls
{
    public partial class ObjectViewer : UserControl
    {
        public ObjectViewer()
        {
            InitializeComponent();
        }

        public TreeView TreeView
        {
            get
            {
                return this.treeView;
            }
        }

        public PropertyGrid PropertyGrid
        {
            get
            {
                return this.propertyGrid;
            }
        }

        public event EventHandler AddingTreeViewNode;

        private void treeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (e.Node.Tag != null)
            {
                this.propertyGrid.SelectedObject = e.Node.Tag;
                this.LoadObjectNode(e.Node, e.Node.Tag);

                MethodInfo[] mis = e.Node.Tag.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.InvokeMethod);
                if (mis != null && mis.Length > 0)
                {
                    ContextMenuStrip ms = new ContextMenuStrip();

                    foreach (MethodInfo mi in mis)
                    {
                        if (!mi.IsSpecialName)
                        {
                            ToolStripMenuItem treeViewContextMenuItem = new ToolStripMenuItem(mi.Name);
                                                      
                            ParameterInfo[] parameters = mi.GetParameters();

                            if (parameters.Length == 0)
                            {
                                if (mi.ReturnType == typeof(void))
                                {
                                    treeViewContextMenuItem.ForeColor = Color.Red;
                                }

                                treeViewContextMenuItem.Click += new EventHandler(treeViewContextMenuItem_Click);

                                ms.Items.Add(treeViewContextMenuItem);
                            }                            
                        }
                    }

                    e.Node.ContextMenuStrip = ms;
                }
            }
        }

        void treeViewContextMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                Object obj=this.treeView.SelectedNode.Tag;

                ToolStripMenuItem menuItem = sender as ToolStripMenuItem;

                MethodInfo mi = obj.GetType().GetMethod(menuItem.Text);

                object rtv=mi.Invoke(obj, null);

                if (rtv != null)
                {
                    if (typeof(System.ValueType).IsInstanceOfType(rtv) || typeof(System.String).IsInstanceOfType(rtv))
                    {
                        MessageBox.Show(rtv.ToString(), "Return Value");
                    }
                    else
                    {
                        Forms.ObjectViewrDialog ovd = new SAE.Forms.ObjectViewrDialog();
                        ovd.Object = rtv;
                        ovd.Text = "Return Value";
                        ovd.ShowDialog();
                    }
                    
                }
                else
                {
                    MessageBox.Show( "Done" , this.ParentForm.Text);
                }
            }
            catch (AmbiguousMatchException)
            {

            }
        }

        public void LoadObjectNode(TreeNode objNode, object obj)
        {
            if (objNode == null)
            {
                objNode = new TreeNode();
                objNode.Tag = obj;
                this.OnAddingTreeViewNode(objNode);
                this.treeView.Nodes.Add(objNode);
                this.LoadObjectNode(objNode, obj);
            }
            else if(objNode.Nodes.Count==0)
            {
                SortedList<string, TreeNode> childNodes=null;

                if (typeof(System.Collections.ICollection).IsInstanceOfType(obj) ||
                    typeof(System.Collections.Generic.ICollection<>).IsInstanceOfType(obj) ||
                    typeof(System.Collections.IEnumerable).IsInstanceOfType(obj) ||
                    typeof(System.Collections.Generic.IEnumerable<>).IsInstanceOfType(obj))
                {
                    childNodes = this.GetItemNodes(obj);
                }
                else
                {
                    childNodes = this.GetPropertyNodes(obj);
                }

                foreach (TreeNode childNode in childNodes.Values)
                {
                    this.OnAddingTreeViewNode(childNode);
                    objNode.Nodes.Add(childNode);

                    object childObj = childNode.Tag;
                    SortedList<string, TreeNode> level2Nodes = null;

					if (typeof(System.Collections.ICollection).IsInstanceOfType(childObj) ||
					typeof(System.Collections.Generic.ICollection<>).IsInstanceOfType(childObj) ||
					typeof(System.Collections.IEnumerable).IsInstanceOfType(childObj) ||
					typeof(System.Collections.Generic.IEnumerable<>).IsInstanceOfType(childObj))
                    {
						level2Nodes = this.GetItemNodes(childObj);
                    }
                    else
                    {
						level2Nodes = this.GetPropertyNodes(childObj);
                    }

                    foreach (TreeNode level2Node in level2Nodes.Values)
                    {
						this.OnAddingTreeViewNode(level2Node);
                        childNode.Nodes.Add(level2Node);
                    }
                }
            }
        }

        private SortedList<string, TreeNode> GetPropertyNodes(object obj)
        {
            SortedList<string, TreeNode> propertyNodes = new SortedList<string, TreeNode>();

            if (obj != null)
            {
                PropertyInfo[] pis = obj.GetType().GetProperties();

                foreach (PropertyInfo pi in pis)
                {
					try
					{
						object propertyValue = pi.GetValue(obj, null);

						if (propertyValue != null &&
							!typeof(DateTime).IsInstanceOfType(propertyValue) &&
							!typeof(string).IsInstanceOfType(propertyValue) &&
							!typeof(ValueType).IsInstanceOfType(propertyValue) &&
							!typeof(System.String).IsInstanceOfType(propertyValue) &&
							!typeof(System.Byte[]).IsInstanceOfType(propertyValue))
						{
							TreeNode propertyNode = new TreeNode(pi.Name);
							propertyNode.ToolTipText = pi.PropertyType.FullName;
							propertyNode.Tag = propertyValue;

                            if (propertyNodes.ContainsKey(pi.Name))
                            {
                                propertyNodes.Add(pi.Name + Guid.NewGuid().ToString(), propertyNode);
                            }
                            else
                            {
                                propertyNodes.Add(pi.Name, propertyNode);
                            }
						}
					}
					catch (TargetInvocationException)
					{
					}
					catch (TargetParameterCountException)
					{
					}
                }
            }

            return propertyNodes;
        }

        private SortedList<string, TreeNode> GetItemNodes(object obj)
        {
            SortedList<string, TreeNode> itemNodes = new SortedList<string, TreeNode>();

            if (obj != null)
            {
                IEnumerator enumtor=null;

                if (typeof(System.Collections.ICollection).IsInstanceOfType(obj) ||
                    typeof(System.Collections.Generic.ICollection<>).IsInstanceOfType(obj))
                {
                    ICollection cOjb = obj as ICollection;
                    enumtor = cOjb.GetEnumerator();
                }
                else if (typeof(System.Collections.IEnumerable).IsInstanceOfType(obj) || 
                    typeof(System.Collections.Generic.IEnumerable<>).IsInstanceOfType(obj))
                {
                    IEnumerable enumOjb = obj as IEnumerable;
                    enumtor = enumOjb.GetEnumerator();                    
                }

                if (enumtor != null)
                {
                    int i = 0;

                    while (enumtor.MoveNext())
                    {
                        TreeNode itemNode = new TreeNode();
                        itemNode.Tag = enumtor.Current;					
                        itemNodes.Add(i.ToString(), itemNode);
                        i++;
                    }
                }
            }

            return itemNodes;
        }

        private void treeView_AfterExpand(object sender, TreeViewEventArgs e)
        {
            if (e.Node.Tag != null)
            {
            }
        }

		private void OnAddingTreeViewNode(TreeNode node)
		{			
			if (string.IsNullOrEmpty(node.Text) && node.Tag != null)
			{
				object item = node.Tag;
                node.ToolTipText = node.Tag.GetType().FullName;

                PropertyInfo piItem = item.GetType().GetProperty("Title");
                node.Text = (piItem == null ? null : piItem.GetValue(item, null).ToString());

                if (string.IsNullOrEmpty(node.Text))
				{
                    piItem = item.GetType().GetProperty("DisplayName");
                    node.Text = (piItem == null ? null : piItem.GetValue(item, null).ToString());
				}

                if (string.IsNullOrEmpty(node.Text))
				{
					piItem = item.GetType().GetProperty("Name");
                    node.Text = (piItem == null ? null : piItem.GetValue(item, null).ToString());
				}

                if (string.IsNullOrEmpty(node.Text))
				{
					piItem = item.GetType().GetProperty("Uri");
                    node.Text = (piItem == null ? null : piItem.GetValue(item, null).ToString());
				}

                if (string.IsNullOrEmpty(node.Text))
                {
                    piItem = item.GetType().GetProperty("Url");
                    node.Text = (piItem == null ? null : piItem.GetValue(item, null).ToString());
                }

                if (string.IsNullOrEmpty(node.Text))
                {
                    piItem = item.GetType().GetProperty("Key");
                    node.Text = (piItem == null ? null : piItem.GetValue(item, null).ToString());
                }

                if (string.IsNullOrEmpty(node.Text))
                {
                    piItem = item.GetType().GetProperty("ID");
                    node.Text = (piItem == null ? null : piItem.GetValue(item, null).ToString());
                }

                if (string.IsNullOrEmpty(node.Text))
                {
                    node.Text = item.ToString();
                }

				node.ToolTipText = item.GetType().ToString();
			}

            if (this.AddingTreeViewNode != null)
            {
                AddingTreeViewNode(node, null);
            }
		}
    }
}
